\epi{``\lstinline{^}''}{\textit{对是否有按位非的运算符的回答。}\\\textsc{KEN THOMPSON}}
\noindent{}
包是函数和数据的集合。
用 \first{\key{package}}{keyword!package} 关键字定义一个包。
文件名不需要与包名一致。包名的约定是使用小写字符。
Go 包可以由多个文件组成，但是使用相同的 \lstinline{package <name>} 这一行。
让我们在文件 \prog{even.go} 中定义一个叫做 \package{even}\index{package!even} 的包。

\lstinputlisting[label=src:even,caption=一个小包]{src/even.go}
名称以大写字母起始的是\emph{可导出}的，可以在包的外部调用（稍候会对此进行讨论）。

现在只需要构建这个包。在 \var{\$GOPATH} 下建立一个目录，复制
\file{even.go} 到这个目录（参阅第 \ref{chap:intro} 章的``\titleref{sec:building a program}''）。

\begin{display}
\pr \user{mkdir $GOPATH/src/even}
\pr \user{cp even.go $GOPATH/src/even}
\pr \user{go build}
\pr \user{go install}
\end{display}

现在就可以在程序 \prog{myeven.go} 中使用这个包：

\lstinputlisting[label=src:myeven,caption=even 包的使用]{src/myeven.go}
\showremarks

\begin{display}
\pr \user{go build myeven.go}
\pr \user{./myeven}
Is 5 even? false
\end{display}

在 Go 中，当函数的首字母大写的时候，函数会被从包中导出（在包外部可见，或者说公有的），
因此函数名是 \func{\emph{E}ven}。如果修改 \prog{myeven.go} 的第 10 行，使用未导出的函数
\func{even.odd}：

\noindent\lstinline{fmt.Printf("Is %d even? %v\n", i, even.odd(i))}

由于使用了\emph{私有}的函数，会得到一个编译错误：
\begin{display}
myeven.go:10: cannot refer to unexported name even.odd
\end{display}

\noindent{}概括来说：
\begin{itemize}
\item 公有函数的名字以\emph{大写}字母开头；
\index{public}
\item 私有函数的名字以\emph{小写}字母开头。
\index{private}
\end{itemize}
这个规则同样适用于定义在包中的其他名字（新类型、全局变量）。
注意，``大写''的含义并不仅限于 US ASCII，它被扩展到了所有大小写字母表
（拉丁文、希腊文、斯拉夫文、亚美尼亚文和埃及古文）。

\section{标识符}
像在其他语言中一样，Go 的命名是很重要的。在某些情况下，它们甚至有语义上的作用：
例如，在包外是否可见决定于首字母是不是大写。因此有必要花点时间讨论一下 Go 程序的命名规则。

使用的规则是让众所周知的缩写保持原样，而不是去尝试到底哪里应该大写。
\lstinline{Atoi}，\lstinline{Getwd}，\lstinline{Chmod}。

驼峰式对那些有完整单词的会很好：\lstinline{ReadFile}，\lstinline{NewWriter}，\lstinline{MakeSlice}。

\subsection{包名}
当包导入（通过 \first{\key{import}}{keyword!import}）时，包名成为了内容的入口。
在\index{package!bytes} 
\begin{lstlisting}
import "bytes"
\end{lstlisting}
之后，导入包的可以调用函数\func{bytes.Buffer}。任何使用这个包的人，
可以使用同样的名字访问到它的内容，因此这样的包名是好的：短的、简洁的、好记的。
根据规则，包名是小写的一个单词；不应当有下划线或混合大小写。
保持简洁（由于每个人都可能需要录入这个名字），不要过早考虑命名冲突。

包名是导入的默认名称。可以通过在导入语句指定其他名称来覆盖默认名称：
\begin{lstlisting}
import bar "bytes"
\end{lstlisting}
函数 \func{Buffer} 现在可以通过 \lstinline{bar.Buffer} 来访问。
这意味着，包名无需全局唯一；在少有的冲突中，可以给导入的包选择另一个名字在局部使用。
在任何时候，冲突都是很少见的，因为导入的文件名会用来做判断，到底是哪个包使用了。

另一个规则是包名就是代码的根目录名；在 \package{src/pkg/compress/gzip} 的包，
作为 \var{compress/gzip} 导入，但名字是 \package{gzip}，
不是 \package{compress\_gzip} 也不是 \package{compressGzip}。\index{package!compress/gzip}

导入包将使用其名字引用到内容上，所以导入的包可以利用这个避免罗嗦。
例如，缓冲类型 \package{bufio}\index{package!bufio} 包的读取方法，叫做 \func{Reader}，而不是
\func{BufReader}，因为用户看到的是 \func{bufio.Reader} 这个清晰、简洁的名字。
更进一步说，由于导入的实例总是它们包名指向的地址，\func{bufio.Reader} 不会与
\func{io.Reader} 冲突。类似的，\func{ring.Ring}（包 \package{container/ring}）创建新实例的函数——在 Go 中定义的构造函数——通常叫做
\func{NewRing}，但是由于 \type{Ring} 是这个包唯一的一个导出的类型，同时，这个包也叫做
\package{ring}\index{package!ring}，所以它可以只称作 \func{New}。
包的客户看到的是 \func{ring.New}。用包的结构帮助你选择更好的名字。

另外一个简短的例子是 \func{once.Do}（参看 \package{sync}）；\func{once.Do(setup)} 读起来很不错，并且
命名为 \lstinline{once.DoOrWaitUntilDone(setup)} 不会有任何帮助。长的名字不会让其变得容易阅读。
如果名字表达了一些复杂并且微妙的内容，更好的办法是编写一些有帮助的注释，而不是将所有信息都放入名字里。

最后，在 Go 中使用\first{混合大小写}{MixedCaps} MixedCaps 或者 mixedCaps，
而不是下划线区分含有多个单词的名字。

%% Advanced Go, leave it
%%\section{Initialization}
%%Every source file in a package can define an \func{init()} function. This function is
%%called after the variables in the package have gotten their value. The
%%\func{init()} function can be used to setup state before the execution
%%begins.

\section{包的文档}
\gomarginpar{这段复制于 \cite{effective_go}。}
每个包都应该有\emph{包注释}，在 \key{package} 前的一个注释块。
对于多文件包，包注释只需要出现在一个文件前，任意一个文件都可以。
包注释应当对包进行介绍，并提供相关于包的整体信息。
这会出现在 \prog{go doc} 生成的关于包的页面上，并且相关的细节会一并显示。
来自官方 \package{regexp} 包的例子：
\begin{display}
/*
    The regexp package implements a simple library for
    regular expressions.

    The syntax of the regular expressions accepted is:

    regexp:
        concatenation { '|' concatenation }
*/
package regexp
\end{display}

每个定义（并且导出）的函数应当有一小段文字描述该函数的行为。来自于
 \package{fmt} 包的例子：
\begin{display}
// Printf formats according to a format specifier and writes to standard
// output. It returns the number of bytes written and any write error
// encountered.
func Printf(format string, a ...interface{}) (n int, err error)
\end{display}

\section{测试包}
在 Go 中为包编写单元测试应当是一种习惯。编写测试需要包含
\package{testing} 包和程序 \first{\prog{go test}}{toolin!go!test}。
两者都有良好的文档。

\prog{go test} 程序调用了所有的测试函数。
\package{even} 包没有定义任何测试函数，执行 \prog{go test}，这样：
\begin{display}
\pr \user{go test}
?       even    [no test files]
\end{display}
在测试文件中定义一个测试来修复这个。测试文件也在包目录中，被命名为 \file{*\_test.go}。
这些测试文件同 Go 程序中的其他文件一样，但是 \prog{go test} 只会执行测试函数。
每个测试函数都有相同的标识，它的名字以 \lstinline{Test} 开头：
\begin{lstlisting}
func TestXxx(t *testing.T)
\end{lstlisting}

编写测试时，需要告诉 \prog{go test} 测试是失败还是成功。测试成功则直接返回。
当测试失败可以用下面的函数标记 \cite{go_doc}。这是非常重要的（参阅 \prog{go doc testing} 或
\prog{go help testfunc} 了解更多）：

\begin{lstlisting}[numbers=none]
func (t *T) Fail()
\end{lstlisting}
\func{Fail} 标记测试函数失败，但仍然继续执行。

\begin{lstlisting}[numbers=none]
func (t *T) FailNow()
\end{lstlisting}
\func{FailNow} 标记测试函数失败，并且中断其执行。
当前文件中的其余的测试将被跳过，然后执行下一个文件中的测试。

\begin{lstlisting}[numbers=none]
func (t *T) Log(args ...interface{})
\end{lstlisting}
\func{Log} 用默认格式对其参数进行格式化，与
\func{Print()} 类似，并且记录文本到错误日志。

\begin{lstlisting}[numbers=none]
func (t *T) Fatal(args ...interface{})
\end{lstlisting}
\func{Fatal} 等价于 \func{Log()} 后跟随 \func{FailNow()}。

将这些凑到一起，就可以编写测试了。首先，选择名字 \file{even\_test.go}。
然后添加下面的内容：
\lstinputlisting[label=src:eventest,caption=even 
包的测试,numbers=right]{src/even_test.go}

注意在第一行使用了 \lstinline{package even}，测试使用与被测试的包使用相同的名字空间。
这不仅仅是为了方便，也允许了测试未导出的函数和结构。然后导入
\package{testing} 包，并且在第 5 行定义了这个文件中唯一的测试函数。
展示的 Go 代码应当没有任何惊异的地方：
检查了 \func{Even} 函数是否工作正常。
现在等待了好久的时刻到了，执行测试：
\begin{display}
\pr \user{go test}
ok      even    0.001s
\end{display}
\noindent{}测试执行并且报告 \texttt{ok}。成功了！

如果重新定义测试函数，就可以看到一个失败的测试：
\begin{lstlisting}
// Entering the twilight zone
func TestEven(t *testing.T) {
        if Even(2) {
                t.Log("2 should be odd!")
                t.Fail()
        }   
}
\end{lstlisting}
然后得到：
\begin{display}
FAIL    even    0.004s
--- FAIL: TestEven (0.00 seconds)
\qquad\qquad2 should be odd!
FAIL
\end{display}
\noindent{}然后你可以以此行事（修复测试的实例）

\begin{lbar}{}
在编写包的时候应当一边写代码，一边写（一些）文档和测试函数。
这可以让你的程序更好，并且它展示了你的努力。
\end{lbar}

The Go test suite also allows you to incorperate example functions which
serve as documentation \emph{and} as tests. These functions need to
start with \texttt{Example}.
\begin{lstlisting}
func ExampleEven() {
    if Even(2) {
        fmt.Printf("Is even\n")
    }
    // Output:
    // Is even
}
\end{lstlisting}
Those last two comments lines are part of the example, \prog{go test} uses those
to check the \emph{generated} output with the text in the comments. If there is
a mismatch the test fails.

\section{常用的包}
标准的 Go 代码库中包含了大量的包，并且在安装 Go 的时候多数会伴随一起安装。
浏览 \file{\$GOROOT/src/pkg} 目录并且查看那些包会非常有启发。
无法对每个包就加以解说，不过下面的这些值得讨论：
\footnote{描述来自包的 \prog{go doc}。额外的解释用斜体。}

\begin{description}
\item[\package{fmt}]{\index{package!fmt}
包 \package{fmt} 实现了格式化的 I/O 函数，这与 C 的 \func{printf} 和 \func{scanf} 类似。
格式化短语派生于 C 。一些短语（\%-序列）这样使用：

\begin{description}
\item[\%v]{默认格式的值。当打印结构时，加号（\%+v）会增加字段名；}
\item[\%\#v]{Go 样式的值表达；}
\item[\%T]{带有类型的 Go 样式的值表达；}
\end{description}

}

\item[\package{io}]{\index{package!io}
这个包提供了原始的 I/O 操作界面。它主要的任务是对 os 包这样的原始的 I/O 
进行封装，增加一些其他相关，使其具有抽象功能用在公共的接口上。
}
\item[\package{bufio}]{\index{package!bufio}
这个包实现了缓冲的 I/O。它封装于
\lstinline{io.Reader}
和
\lstinline{io.Writer}
对象，创建了另一个对象（Reader 和 Writer）在提供缓冲的同时实现了一些文本 I/O 的功能。
}
\item[\package{sort}]{\index{package!sort}
\package{sort} 包提供了对数组和用户定义集合的原始的排序功能。
}
\item[\package{strconv}]{\index{package!strconv}
\package{strconv} 包提供了将字符串转换成基本数据类型，或者从基本数据类型转换为字符串的功能。
}
\item[\package{os}]{\index{package!os}
\package{os} 包提供了与平台无关的操作系统功能接口。其设计是 Unix 形式的。
}
\item[\package{sync}]{\index{package!sync}
\package{sync} 包提供了基本的同步原语，例如互斥锁。
}
\item[\package{flag}]{\index{package!flag}
\package{flag} 包实现了命令行解析。
\emph{参阅 ``\titleref{sec:option parsing}'' 在第 \pageref{sec:option parsing} 页。}
}
\item[\package{encoding/json}]{\index{package!encoding/json}
\package{encoding/json} 包实现了编码与解码 RFC 4627 \cite{RFC4627} 定义的 JSON 对象。
}
\item[\package{html/template}]{\index{package!html/template}
数据驱动的模板，用于生成文本输出，例如 HTML。

将模板关联到某个数据结构上进行解析。模板内容指向数据结构的元素（通常结构的字段或者 map 的键）
控制解析并且决定某个值会被显示。模板扫描结构以便解析，而``游标'' @ 决定了当前位置在结构中的值。
}
\item[\package{net/http}]{\index{package!net/http}
\package{net/http} 实现了 HTTP 请求、响应和 URL 的解析，并且提供了可扩展的 HTTP 服务和基本的 HTTP 客户端。
}
\item[\package{unsafe}]{\index{package!unsafe}
\package{unsafe} 包包含了 Go 程序中数据类型上所有不安全的操作。
\emph{通常无须使用这个。}
}
\item[\package{reflect}]{\index{package!reflect}
\package{reflect} 包实现了运行时反射，允许程序通过抽象类型操作对象。
通常用于处理静态类型 \lstinline|interface{}| 的值，并且通过 \func{Typeof}
解析出其动态类型信息，通常会返回一个有接口类型 \type{Type} 的对象。

\emph{参阅 \ref{chap:interfaces}，第 ``\titleref{sec:introspection and reflection}'' 节}。
}
\item[\package{os/exec}]{\index{package!os/exec}
\package{os/exec} 包执行外部命令。
}
\end{description}

\section{练习}
\input{ex-packages/ex-stack-package.tex}

\input{ex-packages/ex-calc.tex}

\cleardoublepage
\section{答案}
\shipoutAnswer
